home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Gold Medal Software 2
/
Gold Medal Software Volume 2 (Gold Medal) (1994).iso
/
prog
/
asm_0_m.arj
/
DP16.ASM
< prev
next >
Wrap
Assembly Source File
|
1987-02-24
|
32KB
|
1,044 lines
PAGE 61,132
TITLE DataPath 1.6 - Not Copyrighted (nc) 1987 - GDC Software
COMMENT *
DATAPATH.COM - This program attaches itself to MS-DOS or PC-DOS for
automatic search of specified subdirectories or disks for
a program's support ( help, overlay, etc.) files. It will
support CP/M style calls ( CALL 0005h ) as well as normal
MS-DOS calls. Detailed information on use and technical
information is in the file DATAPATH.DOC.
ASSEMBLY - MASM DATAPATH;
LINK DATAPATH;
EXE2BIN DATAPATH.EXE DATAPATH.COM
AUTHOR - Bruce Dubbs
GDC Software
122 Valencia Dr.
Universal City, TX 78148
THIS PROGRAM IS NOT COPYRIGHTED 1987. IT IS RELEASED INTO
THE PUBLIC DOMAIN FOR WHATEVER USE YOU WANT. IF YOU WANT
TO DISTRIBUTE THIS PROGRAM OR USE IT WITH ANY OTHER WAY,
AN ACKNOWLEDGEMENT WOULD BE NICE. *
SUBTTL Basic Definitions and Setup
PAGE
NUL EQU 00H
BEL EQU 07H
LF EQU 0AH
CR EQU 0DH
TRUE EQU 0FFFFH
FALSE EQU NOT TRUE
.SALL ; Supress MACRO listings
SUBTITLE MACRO STRING ; Change the subtitle but
; don't display SUBTTL command
SUBTTL STRING
.LIST
PAGE
ENDM
PRINT MACRO STRING ; Print a string
MOV DX,OFFSET STRING
MOV AH,9
INT 21H
ENDM
CSEG SEGMENT
ASSUME CS:CSEG,DS:CSEG,SS:CSEG,ES:NOTHING
ORG 0
XFER_ADDRESS LABEL BYTE
ORG 80H
DP_LENGTH LABEL BYTE
ORG 81H
DATAPATH LABEL BYTE
ORG 100H
START: JMP INSTALL ; Jump to installation
DW 64 DUP (?)
STACK LABEL WORD
WORK_AREA DB 128 DUP (?)
ID DB 'DataPath 1.6' ; 1.3
;------------------------------------------------------------------------------
.XLIST
SUBTITLE <BDOS redirection module>
BDOS PROC FAR
; In a program designed to run under CP/M, a CALL to location 5h would call
; BDOS. In MS-DOS, CP/M compatability is attempted by inserting a FAR CALL
; at location 5h. From there the first instruction found is a far jump. The
; function request was passed in register CL.
; This routine rearranges the stack, and sets up for a proper INT 21h function
; request.
; Note: CL = 0 (TERMINATE) must be handled specially because the CS segment
; is not compatable with a memory resident DataPath.
CMP CL,0 ; Terminate?
JNE BDOS_2
JMP CS:BDOS_ADDR
BDOS_2: POP AX ; Throw away 0Ah return addr
POP AX ; Now swap the top two words on
POP CS:BDOS_TEMP ; the stack
PUSH AX
PUSH CS:BDOS_TEMP
MOV AH,CL ; Set the function
INT 21H ; and go do it
RET
BDOS_TEMP DW ?
BDOS_ADDR LABEL DWORD
BDOS_OFFSET DW ?
BDOS_SEGMENT DW ?
BDOS ENDP
;------------------------------------------------------------------------------
.XLIST
SUBTITLE <Interrupt 24h (Abort) routine>
ABORT PROC FAR
; This is the fatal error abort routine to check for open drive doors, etc.
; It will be used only when we are searching for a file. We will ignore
; any error and return to the program with carry set.
POP AX ; Discard the INT 24H return
POP AX ; address and flags
POP AX
POP AX ; Restore user registers
POP BX
POP CX
POP DX
POP SI
POP DI
POP BP
POP DS
POP ES
XCHG BP,SP ; Set the carry flag on the
OR BYTE PTR 4[BP],1 ; stack so it will be set
XCHG BP,SP ; after the IRET
IRET
ABORT ENDP
;------------------------------------------------------------------------------
PAGE
; The routines below set and restore the INT 24H fatal error handler.
; They use an INT 21H call that reenters DataPath. The stack will grow a
; little, but the call is just passed to MS-DOS.
SET_ABORT: PUSH AX ; Save registers
PUSH BX
PUSH ES
MOV AX,3524H ; Get INT 24H address
INT 21H
MOV ABORT_OFFSET,BX ; and save it
MOV ABORT_SEGMENT,ES
MOV DX,OFFSET ABORT
MOV AX,2524H ; Set the interrupt address
INT 21H
POP ES ; Restore registers
POP BX
POP AX
RET
CLEAR_ABORT: PUSH AX ; Save registers
PUSH DX
PUSH DS
LDS DX,ABORT_ADDRESS ; Reset address
MOV AX,2524H ; Set the interrupt address
INT 21H
POP DS ; Restore registers
POP DX
POP AX
RET
ABORT_ADDRESS LABEL DWORD
ABORT_OFFSET DW ?
ABORT_SEGMENT DW ?
;------------------------------------------------------------------------------
.XLIST
SUBTITLE <Interrupt 21H intercept>
; When installed, DataPath intercepts all INT 21H call and works on three
; of them.
NEW_21: PUSHF ; Save flags
CMP CS:DATAPATH,'$' ; If null datapath, skip to DOS
JE OLD ; 1.6
CMP AH,0FH ; Is the call 'OPEN' ?
JE OPEN
CMP AH,23H ; Is the call 'FILE SIZE' ?
JE OPEN
CMP AH,0BDH ; Is this 'our' function?
JE OUR_FUNCTION
CMP AH,3DH ; Is it 'OPEN FILE HANDLE' ?
JNE OLD
JMP HANDLE
OLD: POPF ; Restore flags we called with
JMP CS:OLD_21 ; Otherwise don't mess with the
; interrupt
; Check if caller is looking for DataPath
OUR_FUNCTION: PUSH ES ; Save registers 1.2
PUSH CX ; 1.2
PUSH SI ; 1.2
PUSH DI ; 1.2
PUSH CS ; Set destination to us
POP ES ;
MOV DI,OFFSET ID ; Point to our ID 1.2
MOV CX,12 ; 1.2
REPE CMPSB ; See if ID is us 1.2
POP DI ; Restore registers 1.2
POP SI ; 1.2
JCXZ ID_OK ; If zero, ID matches 1.2
POP CX ; Reset registers 1.2
POP ES ; 1.2
JMP OLD ; And continue to DOS 1.2
ID_OK: POP CX ; Reset CX 1.2
ADD SP,2 ; ES stays the same 1.2
NOT BX ; Invert BX to say we're here
POPF
IRET
SAVE_SS DW ? ; Stack Segment storage
SAVE_SP DW ? ; Stack Pointer storage
OLD_21 LABEL DWORD ; Real INT 21H address
OLD_21_OFFSET DW ?
OLD_21_SEGMENT DW ?
VERBOSE DB 0FFH ; TRUE
WRITE_ENABLE DB 0 ; FALSE
.XLIST
SUBTITLE <INT 21H Functions 'OPEN' and 'FILE SIZE'>
; This procedure handles the old CP/M 'OPEN' routine. If the call does not
; directly, a call to the routine 'FIND_FILE' checks any alternate paths.
; If the file is then found, the directory is changed to the found file's
; directory, the file is opened, and the directory is then changed back to
; the original directory.
FUNCTION DB ? ; Calling function
DRIVE_SPECIFIED DB ?
CURRENT_DRIVE DB ?
RESULT DB ?
FCB_OFFSET DW ?
FCB_SEGMENT DW ?
FILENAME DB 13 DUP (?)
; Flags are already pushed
OPEN: STI ; Reenable interrupts
MOV CS:FUNCTION,AH ; Save calling function
CALL CS:OLD_21 ; Try to open the file
CMP AL,0 ; Successful ?
JNE OPEN_2 ; If not, try DataPath
IRET ; Otherwise return
; Search the DataPath
OPEN_2: MOV CS:SAVE_SS,SS ; Save the stack
MOV CS:SAVE_SP,SP
MOV AX,CS ; Set the stack
MOV SS,AX
MOV SP,OFFSET STACK
PUSH BX ; Save the registers
PUSH CX
PUSH DX
PUSH SI
PUSH DI
PUSH DS
PUSH ES
PAGE
; Set up defaults and save FCB data.
MOV ES,AX ; Set string destination seg
MOV SI,DX
MOV CS:ATTRIBUTES,0 ; Set default attributes
MOV CS:FCB_OFFSET,DX ; Save FCB address
MOV CS:FCB_SEGMENT,DS
CLD ; String increase
LODSB ; Get 1st FCB char (bump SI)
CMP AL,0FFH ; Extended FCB ?
JNE OPEN_4
MOV AL,5[SI] ; Get attributes
MOV CS:ATTRIBUTES,AL ; and save
MOV AL,6[SI] ; Get drive specification
ADD SI,7 ; Adjust to point to filename
; Copy filename to a work area as an ASCII string. Also check for wildcards.
; If a wildcard is found, don't search DataPath.
OPEN_4: MOV CS:DRIVE_SPECIFIED,AL; Save drive specification
MOV CX,8
MOV DI,OFFSET FILENAME ; Point to work area
OPEN_5: LODSB ; Transfer filename
CMP AL,'?'
JE OPEN_8A
CMP AL,' ' ; Blanks terminate the string
JE OPEN_6
STOSB
OPEN_6: LOOP OPEN_5
MOV AL,'.' ; Add a '.'
STOSB
MOV CL,3
OPEN_7: LODSB ; Transfer extension to work
CMP AL,'?' ; area
JE OPEN_8A
CMP AL,' '
JE OPEN_8
STOSB
LOOP OPEN_7
OPEN_8: MOV AL,NUL ; Terminate ASCIIZ string
STOSB
PAGE
PUSH CS
POP DS ; DS points to us
MOV RESULT,0FFH ; Set default to not found
MOV DX,OFFSET FILENAME ; ES:DX points to filename
MOV DI,DX
CALL GET_LENGTH
CMP CL,0
JE OPEN_8A
CALL FIND_PATH
JNC OPEN_9 ; File not found
OPEN_8A: JMP OPEN_20
; We found the file. We will now:
; 1. Get the found drive.
; 2. Get the current directory on the found drive.
; 3. Set the found directory on the found drive.
; 4. Set found drive in FCB.
; 5. Open the file.
; 6. Reset the current directory on the found drive.
; 7. If the sspecified FCB drive was not zero, reset it.
OPEN_9: MOV AH,19H ; Get current drive
INT 21H
INC AL ; Set 1=A, 2=B, etc
MOV CURRENT_DRIVE,AL
MOV DI,OFFSET XFER_ADDRESS ; Get found drive
MOV BX,DX
MOV AL,1[BX] ; Check if 2nd char is a ':'
CMP AL,':' ; If drive not specified,
JE OPEN_10 ; then get current drive
MOV AL,CURRENT_DRIVE
ADD AL,'@' ; Make ASCII
JMP SHORT OPEN_11
OPEN_10: MOV AL,[BX] ; Get found drive
OPEN_11: MOV CL,AL ; Save in CL and
STOSB ; memory
MOV AX,'/:' ; Add ':/' (stored backward)
STOSW
MOV SI,DI ; Set up for 'Get Directory'
SUB CL,'@' ; Make drive numeric
MOV DL,CL ; Save in CL
MOV AH,47H ; Get current directory
INT 21H
JC OPEN_20 ; Shouldn't happen
PAGE
MOV DI,END_PATH ; Point to filename
DEC DI ; Point to end of path
MOV AL,NUL ; Make ASCIIZ string
STOSB
MOV DX,BX ; Point to directory
MOV AH,3BH
INT 21H ; Set directory Path
PUSH DS
MOV DX,FCB_OFFSET ; Point to FCB
MOV DS,FCB_SEGMENT
MOV BX,DX
MOV AL,[BX] ; Get 1st char
CMP AL,0FFH ; Check for extended FCB
JNE OPEN_14
ADD BX,7 ; Point to drive specifier
OPEN_14: MOV [BX],CL ; Set drive specifier
MOV AH,CS:FUNCTION ; Now open the file
PUSHF
CALL CS:OLD_21
POP DS
MOV RESULT,AL ; Save result
MOV DX,OFFSET XFER_ADDRESS
MOV AH,3BH
INT 21H ; Reset found directory
MOV AL,DRIVE_SPECIFIED ; If drive was specified,
CMP AL,0 ; reset it
JNE OPEN_16
MOV AL,CURRENT_DRIVE ; otherwise, use current drive
OPEN_16: MOV BX,FCB_OFFSET ; Point to FCB
MOV DS,FCB_SEGMENT
MOV AH,[BX] ; Get 1st character
CMP AH,0FFH ; Check for extended FCB
JNE OPEN_18
ADD BX,7 ; Point to drive
OPEN_18: MOV [BX],AL ; Set drive
PAGE
OPEN_20: POP ES ; Restore all registers
POP DS
POP DI
POP SI
POP DX
POP CX
POP BX
; Note -- interrupts are automatically disabled for one instruction after
; updating a segment register
MOV SS,CS:SAVE_SS
MOV SP,CS:SAVE_SP
MOV AH,CS:FUNCTION
MOV AL,CS:RESULT ; Return result of OPEN
IRET
.XLIST
SUBTITLE <INT 21H Function to 'OPEN FILE HANDLE'>
; This procedure handles the 'OPEN FILE HANDLE' routine. If the call does
; not work directly, a call to the routine 'FIND_FILE' checks any alternate
; paths. If the file is found, the file is then opened.
HANDLE: CLI ; Enable hardware interrupts
MOV CS:CALLER,AX ; Save calling function
CALL CS:OLD_21 ; Try the open as sent
JC HANDLE_0
JMP HANDLE_4 ; Success
; Try data paths
HANDLE_0: MOV CS:SAVE_AX,AX ; Save original error code
MOV CS:SAVE_SS,SS ; Save old SS:SP
MOV CS:SAVE_SP,SP
MOV AX,CS
MOV SS,AX ; SS <- CS
MOV SP,OFFSET STACK ; Set stack pointer
PUSH BX ; Save CPU state
PUSH CX
PUSH DX
PUSH SI
PUSH DI
PUSH DS
PUSH ES
MOV BX,DS
MOV DS,AX ; DS <- CS
MOV ES,BX ; ES <- OLD DS
PAGE
; See if the caller:
; 1. Asked for a open to write, or
; 2. Has a path length not in the range of 1..80 bytes, or
; 3. Had any wildcards in the file name, or
; 4. Specified a directory or drive.
; If any of the above are true, do not search extra paths.
CMP WRITE_ENABLE,TRUE ; See if read only
JE HANDLE_1 ; Skip next if so
MOV AX,CALLER ; Get calling function
CMP AL,0 ; Open for read?
STC ; Set if error
JNE HANDLE_3 ; If not, skip DataPath
HANDLE_1: PUSH BX
MOV BX,DX
CMP ES:BYTE PTR[BX+1],':'; if drive is specified,
JNE HANDLE_2 ; ignore it
ADD DX,2
HANDLE_2: MOV DI,DX ; Set DI for SCASB instructions
POP BX
CALL GET_LENGTH ; Get length of filename
CMP CL,0 ; If zero, return 1.6
STC ; Assume error 1.6
JE HANDLE_3
CALL CHECK_WILD ; Check for wildcard characters
JC HANDLE_3 ; If present, return
MOV ATTRIBUTES,0111B ; Match any attribute
CALL FIND_PATH ; Search for the file
JC HANDLE_3
MOV AX,CALLER ; No error, open the file
PUSHF
CALL OLD_21
JC HANDLE_3 ; Jump if we have an error
MOV HANDLE_NUM,AX
HANDLE_3: POP ES ; Restore all registers
POP DS
POP DI
POP SI
POP DX
POP CX
POP BX
MOV AX,CS:SAVE_AX ; This is original error code
MOV SS,CS:SAVE_SS
MOV SP,CS:SAVE_SP
JC HANDLE_4
MOV AX,CS:HANDLE_NUM ; If no error, return the handle
PAGE
; Insure the flags on the stack are set properly.
HANDLE_4: XCHG BP,SP ; We want to index on SP
JC HANDLE_6
AND BYTE PTR 4[BP],0FEH ; Clear carry on the stack
JMP SHORT HANDLE_8 ; or
HANDLE_6: OR BYTE PTR 4[BP],1 ; Set carry on stack
HANDLE_8: XCHG BP,SP ; Reset registers
IRET ; OK to return
CALLER DW ?
HANDLE_NUM DW ?
SAVE_AX DW ?
;------------------------------------------------------------------------------
.XLIST
SUBTITLE <Subroutines>
; Find the length of the path
GET_LENGTH: CLD ; Strings increase
PUSH DI ; Save start location
MOV AL,NUL
MOV CX,80 ; Set max length of path
REPNE SCASB ; Find a NUL
SUB CX,79 ; Get length of path
NEG CX
MOV CS:NAME_LENGTH,CX ; Save the filename length
POP DI
RET
;------------------------------------------------------------------------------
; Check for Drive, Directory, or wildcards ( ':', '\', '*', or '?' )
CHECK_WILD: MOV BX,OFFSET WILDCARDS ; Point to exceptions
MOV CX,4 ; There are 4 of them
C1: PUSH CX ; Save the count
PUSH DI ; Save the start location
MOV CX,NAME_LENGTH ; Length to scan
MOV AL,[BX] ; Get a character
REPNE SCASB ; See if its there
CMP CL,0 ; Set the flags
POP DI ; Reset start location
POP CX ; Reset count
JNE C2 ; Found exception, no DataPath
INC BX ; else, point to next char
LOOP C1 ; and check for it
CLC
RET ; Return OK
C2: STC ; Error return
RET
NAME_LENGTH DW ?
WILDCARDS DB ':\*?'
;------------------------------------------------------------------------------
PAGE
; The subroutine FIND_PATH checks for the file in question along the
; supplementary DataPath. The logic of the routine is as follows:
; 1. If the DataPath is exhausted, exit with carry set.
; 2. Copy the next DataPath, delimited by a ';' to the working area.
; a. Insure it ends with a backslash.
; 3. Execute DOS call to 'Find First Matching File'.
; a. If file is found, return with DS:DX pointing to the
; path/filename for a subsequent Open call.
; b. Otherwise, goto step 1 above.
; Upon entry, ES:DX points to filename.
ATTRIBUTES DB ?
END_PATH DW ?
FILE_OFFSET DW ?
FILE_SEGMENT DW ?
LAST_PATH DB ?
FIND_PATH PROC NEAR
MOV FILE_OFFSET,DX ; Save file pointers
MOV FILE_SEGMENT,ES
CALL SET_ABORT ; Set our INT 24H handler
CALL SET_DTA ; Set Disk Transfer Address
MOV SI,OFFSET DATAPATH ; Point to DataPath
; Move the path to our work area
MOV AX,CS ; Reset destination to us
MOV ES,AX
MOV LAST_PATH,FALSE ; Not at last path yet
F1: CMP LAST_PATH,TRUE ; Are we done?
JNE F2 ; Continue if done
CALL CLEAR_ABORT ; All done, reset system
CALL RESET_DTA
STC ; Set carry means not found
RET
F2: MOV CX,LENGTH WORK_AREA ; Point to work area
MOV DI,OFFSET WORK_AREA
MOV AX,NUL ; Start AX as two nuls
PAGE
F3: LODSB ; Get a character
CMP AL,';' ; End of path?
JE F6
CMP AL,'$' ; End of path and DataPath?
JE F5
STOSB ; Save the character in memory
MOV AH,AL ; and here to check for '\'
LOOP F3 ; Get next character
F5: MOV LAST_PATH,TRUE ; Set last path flag
F6: CMP AH,NUL ; Check for zero length DataPath
JE F7
MOV AL,'\' ; Is last character a backslash
CMP AH,AL
JE F7
STOSB ; If not, make it a backslash
; Add the filename to the path
F7: MOV END_PATH,DI ; Save pointer to path end
PUSH DS
PUSH SI
MOV SI,FILE_OFFSET
MOV CX,NAME_LENGTH ; Set the length
MOV DS,FILE_SEGMENT ; Point to original filename
REP MOVSB ; Transfer filename
MOVSB ; Including the NUL
POP SI
POP DS
; Find First Matching File
MOV DX,OFFSET WORK_AREA
MOV AH,4EH ; Find first
MOV CH,0
MOV CL,ATTRIBUTES ; Match given attributes
INT 21H ; Find the file
JC F1 ; If not found, check next path
CALL CLEAR_ABORT ; Successful return
CALL RESET_DTA
CLC
RET
FIND_PATH ENDP
;------------------------------------------------------------------------------
PAGE
; Set Disk Transfer Address
SET_DTA: MOV AH,2FH ; Save the old Disk Xfer Addr
INT 21H
MOV DTA_OFFSET,BX
MOV DTA_SEGMENT,ES
MOV AH,1AH ; Set our Disk Xfer Addr
MOV DX,OFFSET XFER_ADDRESS
INT 21H
RET
; Reset Disk Transfer Address
RESET_DTA: PUSH DS
PUSH DX
LDS DX,DTA ; Point to old Disk Xfer Addr
MOV AH,1AH
INT 21H ; Reset it
POP DX
POP DS
RET
DTA LABEL DWORD
DTA_OFFSET DW ?
DTA_SEGMENT DW ?
;------------------------------------------------------------------------------
.XLIST
SUBTITLE <DataPath installation procedure>
; Start of DataPath installation procedure
TRANSIENT LABEL WORD ; Start of transient load
BAD_DOS_MSG DB 'DataPath requires DOS 2.0 or above',CR,LF
DB 'DataPath NOT installed',CR,LF,'$'
RESIDENT_FLAG DB 0 ; False 1.2
HELP DB 0 ; False 1.2
CLEAR_FLAG DB 0 ; False 1.5
PAGE
INSTALL: MOV AX,CS
MOV DS,AX ; INSURE DS IS SET
; Check for DOS 2.0 or above
MOV AH,30H ; Get DOS version
INT 21H
CMP AL,2 ; Is it 2.0 or more?
JGE INSTALL_1 ; Continue if OK
PRINT BAD_DOS_MSG
INT 20H ; TERMINATE
INSTALL_1: MOV AX,3521H ; GET OLD INT 21 ADDR
INT 21H
MOV OLD_21_OFFSET,BX ; SAVE IT
MOV OLD_21_SEGMENT,ES
; Check if DataPath is already installed by calling a special (our own)
; function of INT 21H.
MOV AH,0BDH ; Our interrupt
MOV SI,OFFSET ID ; Point to name 1.2
XOR BX,BX ; Insure BX is zero
INT 21H ; See if DataPath is there
INC BX ; If so, BX will now be zero
JNZ INSTALL_3
; DataPath is already there
MOV RESIDENT_FLAG,TRUE
JMP SHORT INSTALL_4
; Set new interrupt 21 address
INSTALL_3: MOV DX,OFFSET NEW_21 ; POINT TO OFFSET
MOV AX,2521H ; UPDATE THE INTERRUPT
INT 21H
PAGE
; Set the CP/M BDOS Entry Point for compatability
MOV BX,6
LES BX,[BX] ; GET ADDRESS OF CALL TO CP/M
MOV AX,ES:1[BX] ; AND SAVE IT
MOV BDOS_OFFSET,AX
MOV AX,ES:3[BX]
MOV BDOS_SEGMENT,AX
MOV DX,OFFSET BDOS
MOV ES:1[BX],DX ; SET OUR ADDRESS INTO MS-DOS
MOV ES:3[BX],DS
; If DataPath program is not resident OR a new DataPath is passed, then
; transfer the new Datapath
INSTALL_4: CALL CHECK_SWITCHES ; Set up switches
CALL SQUEEZE_PATH ; Remove illegal characters 1.5
CMP RESIDENT_FLAG,FALSE
JE INSTALL_5
CMP CLEAR_FLAG,TRUE
JE INSTALL_5
CMP DP_LENGTH,0
JE INSTALL_6
INSTALL_5: CALL SET_DATAPATH
; If a new DataPath is not passed, or we are in VERBOSE mode, display the
; current DataPath
CMP HELP,TRUE ; Always display if help 1.2
JE INSTALL_6 ; is set 1.2
CMP ES:VERBOSE,TRUE
JE INSTALL_6
CMP DP_LENGTH,0
JNE INSTALL_8
INSTALL_6: CALL DISPLAY
; Just terminate if we are already resident
INSTALL_8: CMP CS:RESIDENT_FLAG,TRUE
JNE INSTALL_9
MOV AX,4C00H ; OK RETURN
INT 21H ; TERMINATE
; Exit but stay resident - set paragraphs to save
PARAS = (TRANSIENT-XFER_ADDRESS+15) SHR 4 ; 1.5
INSTALL_9: MOV DX,PARAS ; SET LENGTH TO RESERVE 1.2
MOV AX,3100H
INT 21H ; TERMINATE & STAY RESIDENT
PAGE
; Transfer the DataPath but do some pre-processing
SET_DATAPATH PROC NEAR
CLD ; INCREMENT STRINGS
MOV SI,OFFSET DATAPATH ; POINT TO SOURCE CS:81
MOV DI,SI ; POINT TO DEST ES:81
MOV CL,DP_LENGTH ; GET LENGTH OF PASSED STRING
MOV CH,0
CMP CLEAR_FLAG,TRUE ; IF CLEAR_FLAG IS SET 1.5
JE SET_9 ; SET NULL DATAPATH 1.5
CMP RESIDENT_FLAG,TRUE ; IF RESIDENT THEN ES WAS SET
JE SET_2 ; BY INT 21H FUNCTION 'BD'h
PUSH CS ; ELSE SET TO CS
POP ES
CMP HELP,TRUE ; IF HELP AND NOT RESIDENT, 1.2
JE SET_9 ; SET NULL DATAPATH 1.2
SET_2: CMP HELP,TRUE ; IF HELP SET, DON'T RESET 1.2
JE SET_10 ; DATAPATH 1.2
SET_4: LODSB ; GET A CHARACTER
CMP AL,' ' ; THROW AWAY NON PRINTING
JBE SET_8 ; CHARACTERS
CMP AL,'z' ; AND OTHER WEIRD CHARS
JA SET_8
CMP AL,'a' ; CONVERT CHARS TO UPPER CASE
JB SET_7
AND AL,0DFH
SET_7: STOSB ; SAVE THE CHARACTER
SET_8: LOOP SET_4
SET_9: MOV AL,'$' ; STORE A TERMINATING $
STOSB
SET_10: RET
SET_DATAPATH ENDP
CHECK_ILLEGAL PROC NEAR ; 1.3
PUSH CX ; SAVE REGISTERS 1.3
PUSH DI ; 1.3
PUSH ES ; 1.3
PUSH CS ; SET ES=CS 1.3
POP ES ; 1.3
MOV CX,10 ; CHECK 10 CHARACTERS 1.3
MOV DI,OFFSET ILLEGAL_CHARS ; 1.3
REPNE SCASB ; SEE IF WE HAVE ILLEGAL 1.3
CLC ; ASSUME CHAR OK 1.3
JNE CHECK_ILLEGAL_1 ; JUMP IF NO MATCHES 1.3
STC ; CHAR IS ILLEGAL 1.3
CHECK_ILLEGAL_1: POP ES ; RESTORE REGISTERS 1.3
POP DI ; 1.3
POP CX ; 1.3
RET ; 1.3
CHECK_ILLEGAL ENDP ; 1.3
ILLEGAL_CHARS DB '$"[]*?+=<>' ; 1.3
.XLIST
SUBTITLE <Display Subroutine>
; This procedure outputs DataPath info to the screen
DISPLAY PROC NEAR
PRINT INFO ; Print heading
CMP RESIDENT_FLAG,TRUE ; If first time say installed
JE DISPLAY_1
PRINT INSTALLED
DISPLAY_1: PRINT CRLF
PRINT NC ; Print our name
PRINT CRLF2 ; Skip a line
PRINT VERBOSE_MSG ; Print verbose status
CMP ES:VERBOSE,TRUE
JE DISPLAY_2
PRINT OFF
JMP SHORT DISPLAY_3
DISPLAY_2: PRINT ON
DISPLAY_3: PRINT WRITE_ACCESS ; Print open for write status
CMP ES:WRITE_ENABLE,TRUE
JE DISPLAY_4
PRINT OFF
JMP SHORT DISPLAY_5
DISPLAY_4: PRINT ON
DISPLAY_5: PRINT CRLF ; Skip a line
PRINT DATAPATH_MSG ; Tell the current DataPath
PUSH DS
PUSH ES
POP DS ; POINT TO DATAPATH
PRINT DATAPATH
POP DS
PRINT CRLF2
CMP HELP,TRUE ; 1.2
JNE DISPLAY_6 ; 1.2
PRINT USAGE ; 1.2
DISPLAY_6: RET
DISPLAY ENDP
PAGE
INFO DB 'DataPath version 1.6 $' ; 1.5
INSTALLED DB 'Installed$'
NC DB '(nc) 1987 by GDC Software$'
VERBOSE_MSG DB 'Verbose mode is $'
WRITE_ACCESS DB 'Write access is $'
ON DB 'on',CR,LF,'$' ; 1.2
OFF DB 'off',CR,LF,'$' ; 1.2
DATAPATH_MSG DB 'Current DataPath=$'
CRLF2 DB CR,LF
CRLF DB CR,LF,'$'
USAGE DB 'DataPath usage:',CR,LF
DB ' DataPath path1 [;path2...] [/V] [/Q] [/R] [/W]'
DB ' [/C] [/H]',CR,LF ; 1.5
DB ' where path1, path2... are the paths to '
DB 'search for files',CR,LF
DB ' /V sets verbose mode [default]',CR,LF
DB ' /Q sets quiet mode',CR,LF
DB ' /R sets read only mode [default]',CR,LF
DB ' /W allows opens for writing',CR,LF
DB ' /C clears the DataPath',CR,LF ; 1.5
DB ' /H writes this message',CR,LF,'$'
.XLIST
SUBTITLE <Check Switches Subroutine>
; This procedure checks for a /W, /R, /V, /C, and /Q and sets the VERBOSE,
; WRITE_ENABLE, and CLEAR_FLAG flags accordingly.
CHECK_SWITCHES PROC NEAR
CMP RESIDENT_FLAG,TRUE ; If resident ES is set to
JE SWITCH_1 ; resident portion of DataPath
PUSH CS ; otherwise use CS
POP ES
SWITCH_1: CLD ; Scan for a '/'
MOV AL,'/'
XOR CX,CX
MOV CL,DP_LENGTH
MOV DI,OFFSET DATAPATH
PUSH ES
PUSH DS ; Set ES to point to us
POP ES
REPNZ SCASB
POP ES ; Restore ES
JCXZ SWITCH_9 ; All done -- return
MOV AL,[DI] ; Get the character after the /
AND AL,0DFH ; Make upper case
MOV WORD PTR[DI-1],' ' ; Blank out /x
CMP AL,'V' ; /V --> set VERBOSE
JNE SWITCH_2
MOV ES:VERBOSE,TRUE
JMP SHORT SWITCH_1
SWITCH_2: CMP AL,'Q' ; /Q --> clear VERBOSE
JNE SWITCH_3
MOV ES:VERBOSE,FALSE
JMP SHORT SWITCH_1
SWITCH_3: CMP AL,'R' ; /R --> Only work on files
JNE SWITCH_4 ; opened to read
MOV ES:WRITE_ENABLE,FALSE
JMP SHORT SWITCH_1
SWITCH_4: CMP AL,'W' ; /W --> Work on files for
JNE SWITCH_5 ; read or write
MOV ES:WRITE_ENABLE,TRUE
JMP SHORT SWITCH_1
SWITCH_5: CMP AL,'H' ; /H --> Type usage message 1.2
JNE SWITCH_6
MOV HELP,TRUE
JMP SHORT SWITCH_1
SWITCH_6: CMP AL,'C' ; /C --> Clear DataPath 1.5
JNE SWITCH_8
MOV CLEAR_FLAG,TRUE
JMP SHORT SWITCH_1
SWITCH_8: PRINT OPTION_ERROR ; Bad switch. Say so and give
MOV HELP,TRUE ; help
SWITCH_9: RET
OPTION_ERROR DB BEL,'SWITCH ERROR',CR,LF,'$'
CHECK_SWITCHES ENDP
.XLIST
SUBTITLE <Squeeze Path Subroutine>
; This procedure removes non-printing and illegal characters from the passed
; DataPath
SQUEEZE_PATH PROC NEAR
PUSH ES ; Save pointer
PUSH DS ; Make sure we point to local
POP ES ; DataPath
MOV AH,0
MOV CL,DP_LENGTH ; Set length of command tail
MOV CH,AH
MOV SI,OFFSET DATAPATH ; Point to command tail
MOV DI,SI
JCXZ SQZ_3 ; If length is zero, return
SQZ_1: LODSB ; Get a character
CMP AL,' ' ; Check if non-printing
JLE SQZ_2 ; Skip if it is
CALL CHECK_ILLEGAL ; Check for illegal pathname chars
JC SQZ_2 ; Skip those too
INC AH ; Char OK, count it
STOSB ; Save it
SQZ_2: LOOP SQZ_1 ; Work through the string
MOV DP_LENGTH,AH ; Save the new length
SQZ_3: POP ES ; Restore ES
RET
SQUEEZE_PATH ENDP
CSEG ENDS
END START